package com.asen.commons.core.jdbc.impl;

import com.asen.commons.core.jdbc.Jdbc;
import com.asen.commons.core.jdbc.builder.SqlBuilder;
import com.asen.commons.core.jdbc.param.ParamStatementSetter;
import com.asen.commons.core.jdbc.util.LogUtils;
import com.asen.commons.utils.BaseAssert;
import com.asen.commons.utils.SpringUtil;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlRowSetResultSetExtractor;
import org.springframework.jdbc.support.rowset.SqlRowSet;

import javax.sql.DataSource;
import java.util.List;
import java.util.Map;

/**
 * MySql实现
 *
 * @author Gary
 * @version 1.0
 * @date 2018-11-09
 */
public class JdbcImpl implements Jdbc {

    private static LogUtils logger = LogUtils.getLogger(JdbcImpl.class);

    private DataSource dataSource;

    private JdbcTemplate jdbcTemplate;

    @Override
    public int update(SqlBuilder builder) {
        String sql = builder.getSql();
        ParamStatementSetter params = builder.getParams();
        logger.logSql(sql, params);
        long begin = System.currentTimeMillis();
        int result = 0;
        if (params.isEmpty()) {
            result = getTemplate().update(sql);
        } else {
            result = getTemplate().update(sql, params);
        }
        logger.logResult(result, begin, System.currentTimeMillis());
        return result;
    }

    @Override
    public int update(String sql) {
        logger.logSql(sql);
        long begin = System.currentTimeMillis();
        int result = getTemplate().update(sql);
        logger.logResult(result, begin, System.currentTimeMillis());
        return result;
    }

    @Override
    public List<Map<String, Object>> query(String sql) {
        logger.logSql(sql);
        long begin = System.currentTimeMillis();
        List<Map<String, Object>> result = getTemplate().queryForList(sql);
        logger.logResult(result.size(), begin, System.currentTimeMillis());
        return result;
    }

    @Override
    public <T> List<T> query(String sql, Class<T> elementType) {
        logger.logSql(sql);
        long begin = System.currentTimeMillis();
        List<T> list = getTemplate().queryForList(sql, elementType);
        logger.logResult(list.size(), begin, System.currentTimeMillis());
        return list;
    }

    @Override
    public <T> List<T> query(String sql, RowMapper<T> rowMapper) {
        logger.logSql(sql);
        long begin = System.currentTimeMillis();
        List<T> list = getTemplate().query(sql, rowMapper);
        logger.logResult(list.size(), begin, System.currentTimeMillis());
        return list;
    }

    @Override
    public <T> List<T> query(final String sql, final ResultSetExtractor<List<T>> rse) {
        logger.logSql(sql);
        long begin = System.currentTimeMillis();
        List<T> list = getTemplate().query(sql, rse);
        logger.logResult(list.size(), begin, System.currentTimeMillis());
        return list;
    }

    @Override
    public <T> List<T> query(SqlBuilder builder, final ResultSetExtractor<List<T>> rse) {
        String sql = builder.getSql();
        ParamStatementSetter params = builder.getParams();
        logger.logSql(sql, params);
        long begin = System.currentTimeMillis();

        List<T> list = null;
        if (params == null || params.isEmpty()) {
            list = getTemplate().query(sql, rse);
        } else {
            list = getTemplate().query(sql, builder.getParams(), rse);
        }
        logger.logResult(list.size(), System.currentTimeMillis() - begin);
        return list;
    }

    @Override
    public SqlRowSet queryForRowSet(String sql) {
        logger.logSql(sql);
        long begin = System.currentTimeMillis();
        SqlRowSet sqlRowSet = getTemplate().queryForRowSet(sql);
        logger.logResult(1, System.currentTimeMillis() - begin);
        return sqlRowSet;
    }

    @Override
    public SqlRowSet queryForRowSet(String sql, ParamStatementSetter pss) {
        logger.logSql(sql, pss);
        long begin = System.currentTimeMillis();
        SqlRowSet sqlRowSet = getTemplate().query(sql, pss, new SqlRowSetResultSetExtractor());
        logger.logResult(1, System.currentTimeMillis() - begin);
        return sqlRowSet;
    }

    @Override
    public void execute(String sql) {
        logger.logSql(sql);
        long begin = System.currentTimeMillis();
        getTemplate().execute(sql);
        logger.logResultUnknown(System.currentTimeMillis() - begin);
    }

    @Override
    public int[] batchUpdate(String... sql) {
        for (int i = 0; i < sql.length; i++) {
            logger.logSql(sql[i]);
        }
        long begin = System.currentTimeMillis();
        int[] ints = getTemplate().batchUpdate(sql);
        logger.logResultUnknown(System.currentTimeMillis() - begin);
        return ints;
    }

    @Override
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    private JdbcTemplate getTemplate() {
        if (jdbcTemplate == null) {
            synchronized (JdbcImpl.class) {
                jdbcTemplate = SpringUtil.getBean(JdbcTemplate.class);
                if (jdbcTemplate == null) {
                    if (dataSource == null) {
                        dataSource = SpringUtil.getBean(DataSource.class);
                    }
                    BaseAssert.notNull(dataSource, "数据源dataSource不存在！");
                    jdbcTemplate = new JdbcTemplate(dataSource);
                }
            }
        }

        if (jdbcTemplate.getDataSource() == null) {
            if (dataSource == null) {
                dataSource = SpringUtil.getBean(DataSource.class);
            }
            BaseAssert.notNull(dataSource, "数据源dataSource不存在！");
            jdbcTemplate.setDataSource(dataSource);
        }

        return jdbcTemplate;
    }

    @Override
    public DataSource getDataSource() {
        return getTemplate().getDataSource();
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

}
